/* 
 * File:   rpc-fs_cliente.c
 * Author: Juan Manuel Cortez
 *
 * Created on 24 de agosto de 2009, 18:30
 */

#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include "rpc-fs.h"

#define FILE_PACKAGE_LENGTH 512
#define MAX_STRING_SIZE 512
#define ERROR -1
int isfirst = 1;
char cwd[MAX_STRING_SIZE];
CLIENT *rpc_client;

void create_rpc_client(char *host) {
    rpc_client = clnt_create(host, RPC_FS,
            RPC_FS_VER,
            "TCP");

    if (rpc_client == (CLIENT *) NULL) {
        clnt_pcreateerror(host);
        exit(1);
    }
}

void ls(void) {
    if (isfirst == 1) {
        isfirst = 0;
        getcwd(cwd, MAX_STRING_SIZE);
    }
    // estructuras mediante las cuales leeeremos el contenido del directorio
    DIR *dp1;
    struct dirent *dirp;

    // abrimos el directorio
    dp1 = opendir(cwd);

    // si no se puede abrir el directorio...
    if (!dp1) {
        printf("No se pudo leer el directorio.\n");
    } else {
        // leemos contenido del directorio y agregamos los nombres
        // de archivos o directorios al buffer, descartando el directorio
        // actual y el 'padre'
        while ((dirp = readdir(dp1)) != NULL) {
            if (strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "..") == 0)
                continue;
            // si es un directorio, agrego [DIR] a la salida
            if (dirp->d_type == 0x004)
                printf("%s - [DIR]\n", dirp->d_name);
            else
                printf("%s\n", dirp->d_name);

        }
        closedir(dp1);
    }
}

void cd(char *argument) {
    // si es la primera vez que se ejecuta la función,
    // seteamos el directorio de trabajo actual
    if (isfirst == 1) {
        isfirst = 0;
        getcwd(cwd, MAX_STRING_SIZE);
    }

    if (chdir(argument) == 0) {
        getcwd(cwd, MAX_STRING_SIZE);
        printf("Se cambió correctamente el directorio.\nEl directorio actual es '%s'.\n", cwd);
    } else {
        printf("No se pudo cambiar de directorio.\nUd. intentó cambiar a '%s'\n", argument);
    }
}

void execute(CLIENT *cliente, char *command, char *argument, int argc) {
    //// RLS ////
    if (strcmp(command, "rls") == 0) {
        printf("%s\n", rls_1(NULL, cliente));
    } else

        //// RCD ////
        if (strcmp(command, "rcd") == 0) {
        if (argc < 3) {
            printf("Debe ingresar el directorio de destino.\n");
            return;
        }
        printf("Resultado:\n%s\n", rcd_1(argument, cliente));
    } else

        //// GET ////
        if (strcmp(command, "get") == 0) {
        if (argc < 3) {
            printf("Debe ingresar el archivo a descargar.\n");
            return;
        }
        // puntero al archivo que se crea del lado del cliente
        FILE * file = NULL;

        // entrada del 'get'
        get_input *input = (get_input *) malloc(sizeof (get_input));
        // salida del 'get'
        get_output *output;
        // nombre del archivo a 'descargar'
        input->file_name = strdup(argument);

        // primera vuelta...
        input->count = 0;
        // mientras el servidor mande el bloque completo
        do {
            output = get_1(input, cliente);
            if (output->count > 0) {
                if (file == NULL)
                    file = fopen(argument, "w");
                // escribo el bloque del lado del cliente
                fwrite(output->bloque, sizeof (char), output->count, file);
                // preparo la llamada siguiente
                input->count++;
                // traigo el siguiente bloque
            }
        } while (output->count == FILE_PACKAGE_LENGTH);
        if (output->count != ERROR) {
            printf("Resultado:\nSe descargó correctamente el archivo '%s'.\n"
                    "Se transmitieron %i bytes en total.\n",
                    input->file_name,
                    (input->count - 1) * FILE_PACKAGE_LENGTH + output->count);
        } else {
            printf("Ocurrió un error al intentar descargar el archivo.\n"
                    "El archivo '%s' no existe o el servidor no tiene permiso para leerlo.\n",
                    input->file_name);
        }
        if (file != NULL)
            // cierro el archivo
            fclose(file);

        free(input);
    } else

        //// PUT ////
        if (strcmp(command, "put") == 0) {
        if (argc < 3) {
            printf("Debe ingresar el archivo a subir.\n");
            return;
        }
        // puntero al archivo que se crea del lado del cliente
        FILE * put_file = fopen(argument, "r");

        if (put_file != NULL) {
            // entrada del 'put'
            put_input *input = (put_input *) malloc(sizeof (put_input));
            int received_bytes = 0;
            // nombre del archivo a 'subir'
            input->file_name = strdup(argument);
            // primera vuelta...
            input->count = 0;

            // mientras los bytes leidos llenen un 'paquete'
            do {
                input->offset = fread(input->data, sizeof (char), FILE_PACKAGE_LENGTH, put_file);
                received_bytes = *put_1(input, cliente);
                // incrementó contador y avanzo a la siguiente vuelta
                input->count++;
            } while (received_bytes == FILE_PACKAGE_LENGTH);
            // cuando llegué al final de archivo, y leí menos de un 'paquete' entero
            if (received_bytes != ERROR) {
                printf("Se transfirió con éxito el archivo '%s' al servidor.\n"
                        "En total, se transfirieron %i bytes.\n",
                        input->file_name,
                        FILE_PACKAGE_LENGTH * (input->count - 1) + received_bytes);
            } else {
                // si el 'put' devolvió -1, algo salió mal
                printf("No se pudo subir el archivo '%s' al servidor.\n", argument);
            }
            free(input);
            fclose(put_file);
        } else
            printf("No se pudo abrir el archivo '%s'.\n", argument);
    } else
        //// LS ////
        if (strcmp(command, "ls") == 0) {
        ls();
    } else

        //// CD ////
        if (strcmp(command, "cd") == 0) {
        if (argc < 3) {
            printf("Debe indicar el directorio.\n");
            return;
        }
        cd(argument);
    } else
        printf("Operando '%s' no reconocido.\nSolo se aceptan 'put', 'get', 'ls', rls', 'cd' y 'rcd'.\n", command);
}

void run_client(void) {
    char *input = (char *) malloc((MAX_STRING_SIZE + 4) * sizeof (char));
    char *command = (char *) malloc((MAX_STRING_SIZE + 4) * sizeof (char));
    char *argument = (char *) malloc((MAX_STRING_SIZE + 4) * sizeof (char));
    int i, j, k, argc;
    printf(">>> ");
    while (strcmp(gets(input), "exit") != 0) {
        for (i = 0, j = 0, k = 0; i < strlen(input); i++) {
            if (input[i] == ' ') {
                while (input[++i] == ' ');
                command[j] = '\0';
            }

            if (i == j)
                command[j++] = input[i];
            else
                argument[k++] = input[i];

        }
        if (strlen(argument) == 0)
            argc = 0;
        else
            argc = 3;
        if (k == 0)
            command[j] = '\0';
        else
            argument[k] = '\0';
        execute(rpc_client, command, argument, argc);


        printf(">>> ");
    }
}

int main(int argc, char** argv) {
    if (argc < 2) {
        printf("Ingrese la IP del servidor.\n");
        exit(0);
    }
    create_rpc_client(argv[1]);
    run_client();

    return (EXIT_SUCCESS);
}